﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Text;
using System.Web.Mvc;
using ChiakiYu.Model.Permissions;
using ChiakiYu.Web.Controllers;

namespace ChiakiYu.Web
{
   public static class ActionPermissionService
    {
        /// <summary>
        ///     使用Descriptor,取程序集中所有Action的元数据
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Permission> GetAllActionByAssembly()
        {
            var result = new List<Permission>();

            var types = Assembly.GetExecutingAssembly().GetTypes(); //取程序集中的全部类型
            //取控制器
            foreach (var type in types)
            {
                if (type.BaseType == typeof (BaseController)) //如果是BaseController
                {
                    //反射controller
                    var controller = new ReflectedControllerDescriptor(type);
                    //取controller的Action,共有实例方法
                    var actions = controller.GetCanonicalActions();
                    //controller的EnablePermissionAttribute
                    var controllerAttribute = GetAttribute(controller); 
                    //屏蔽没有开启验证的controller
                    if (!controllerAttribute.Enabled) continue;

                    //构建权限
                    foreach (var action in actions)
                    {
                        //action的EnablePermissionAttribute
                        var actionAttribute = GetAttribute(action); 
                        //屏蔽没有开启验证的action
                        if (!actionAttribute.Enabled) continue;
                        //创建权限
                        var ap = new Permission
                        {
                            Action = action.ActionName,
                            Controller = controller.ControllerName,
                            ControllerDescription = controllerAttribute.Description,
                            ActionDescription = actionAttribute.Description,
                            Params = FormatParams(action)
                        };
                        result.Add(ap);
                    }
                }
            }
            return result;
        }

        /// <summary>
        ///     取Controller或者Action的EnablePermissionAttribute
        /// </summary>
        /// <param name="attributeProvider"></param>
        /// <returns></returns>
        public static EnablePermissionAttribute GetAttribute(ICustomAttributeProvider attributeProvider)
        {
            var result = new EnablePermissionAttribute(string.Empty, false);
            //取自定义特性数组
            var enablePermission = attributeProvider.GetCustomAttributes(typeof (EnablePermissionAttribute), false);
            if (enablePermission.Length > 0)
                result = enablePermission[0] as EnablePermissionAttribute;
            return result;
        }

        /// <summary>
        ///     格式化Action的参数字符串
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        private static string FormatParams(ActionDescriptor action)
        {
            var param = action.GetParameters();
            var result = new StringBuilder();
            if (param.Length > 0)
            {
                foreach (var item in param)
                {
                    result.Append(string.Format("{0} {1}, ", item.ParameterType, item.ParameterName));
                }
                return result.ToString().TrimEnd(',');
            }
            return string.Empty;
        }

        #region 使用反射

        /// <summary>
        ///     使用反射，获取Action的信息
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Permission> GetAllActionByAssembly_01()
        {
            var result = new List<Permission>();
            //取程序集中的全部类型
            var types = Assembly.GetExecutingAssembly().GetTypes();

            foreach (var type in types)
            {
                if (type.BaseType != null && type.BaseType.Name == "BaseController") //如果是BaseController
                {
                    //取类型的方法，类型为实例方法，公共方法
                    var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public);
                    foreach (var method in methods)
                    {
                        //因存在异步与同步方法，所以统一用返回类型的tostring方法
                        var returnType = method.ReturnType.ToString();

                        if (returnType.Contains("ActionResult")) //如果是ActionResult
                        {
                            if (method.DeclaringType != null)
                            {
                                var ap = new Permission
                                {
                                    Action = method.Name,
                                    Controller =
                                        method.DeclaringType.Name.Substring(0, method.DeclaringType.Name.Length - 10),
                                    /* 去掉“Controller”后缀*/
                                    Params = FormatParams(method)
                                };
                                //取Action的描述
                                var attrs = method.GetCustomAttributes(typeof (DescriptionAttribute), true);
                                if (attrs.Length > 0)
                                {
                                    ap.ActionDescription = (attrs[0] as DescriptionAttribute).Description;
                                }

                                result.Add(ap);
                            }
                        }
                    }
                }
            }
            return result;
        }

        /// <summary>
        ///     格式化Method的参数字符串
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public static string FormatParams(MethodInfo method)
        {
            var param = method.GetParameters();
            var result = new StringBuilder();
            if (param.Length > 0)
            {
                foreach (var item in param)
                {
                    result.AppendLine(string.Format("Type:{0}, Name:{1}; ", item.ParameterType, item.Name));
                }
                return result.ToString();
            }
            return null;
        }

        #endregion
    }
}